package cn.sh.library.gmwx.sparql.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.ontoware.rdf2go.model.Model;
import org.springframework.stereotype.Repository;

import com.hp.hpl.jena.vocabulary.RDFS;
import cn.sh.library.gmwx.annotation.GraphDefine;
import cn.sh.library.gmwx.base.Constant;
import cn.sh.library.gmwx.base.Namespace;
import cn.sh.library.gmwx.bean.WorkSearchBean;
import cn.sh.library.gmwx.common.ModelManager;
import cn.sh.library.gmwx.config.AppConfig;
import cn.sh.library.gmwx.dao.impl.BaseDaoImpl;
import cn.sh.library.gmwx.dto.Pager;
import cn.sh.library.gmwx.dto.QueryResult;
import cn.sh.library.gmwx.sparql.MergeParts;
import cn.sh.library.gmwx.sparql.RdfQuery;
import cn.sh.library.gmwx.sparql.SparqlExecution;
import cn.sh.library.gmwx.sparql.WorkSparql;
import cn.sh.library.gmwx.utils.RDFUtils;

@Repository
@GraphDefine(name = Constant.GRAPH_WORK)
public class WorkSparqlImpl extends BaseDaoImpl implements WorkSparql {
    @Resource
    private AppConfig appConfig;

    @Override
    public QueryResult<Map<String, String>> searchWorks(WorkSearchBean search, String order, Pager pager) {
//        Model model_op = ModelManager.get(getModel(Constant.GRAPH_UNIFY));
        search.setRemote(appConfig.getRemote());

        String clause = MergeParts.workSearch(search);
        
      //排序 BY_CM
    	String sort = "";
    	if(StringUtils.isNotBlank(search.getTitleSort())) {
    		if("0".equals(search.getTitleSort())) {
    			sort += "order by asc (?title)";
    		}
    		if("1".equals(search.getTitleSort())) {
    			sort += "order by desc (?title)";
    		}
    	}
    	if(StringUtils.isNotBlank(search.getPersonSort())) {
    		if("0".equals(search.getPersonSort())) {
    			sort += "order by asc (?creator)";
    		}
    		if("1".equals(search.getPersonSort())) {
    			sort += "order by desc (?creator)";
    		}
    	}
        
        QueryResult<Map<String, String>> result = new QueryResult<>();

//        if ("on".equals(search.getPersonPre())) {
//            ArrayList results = SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_COUNT_WORK_Q.toString(clause), "count");
//
//            Long count = Long.parseLong(RDFUtils.getValue(((Map) results.get(0)).get("count").toString()));
//
//            result.setTotalrecord(count);
//            if(count > 0) {
//                results = SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_QUERY_WORK_Q.toString(clause, order,  pager.getStartIndex(), pager.getPageSize()), "uri");
//
//                for (int i=0; i<results.size(); i++) {
//                    String uri = ((Map) results.get(i)).get("uri").toString();
//                    Map info = (Map) SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_QUERY_WORK_INFO.toString(uri), "creator", "note", "series", "label").get(0);
//                    ((Map) results.get(i)).put("creator", info.get("creator") != null ? info.get("creator").toString() : "");
//                    ((Map) results.get(i)).put("note", info.get("note") != null ? info.get("note").toString() : "");
//                    ((Map) results.get(i)).put("label", info.get("label") != null ? RDFUtils.getValue(info.get("label").toString()) : "");
//                    ((Map) results.get(i)).put("hor", this.getCoverHor(uri));
//                }
//                result.setResultList(RDFUtils.transformListMap(results));
//            }
//        } else {
            Long count = null;
            ArrayList results = new ArrayList();

            if (pager.getRowCount() == null) {
                pager.setRowCount(Long.parseLong("0"));
            }

            if (isSearchBlank(search)) {
                if (pager.getRowCount() == 0) {
                    if (StringUtils.isNotBlank(search.getAudience())) {
                        results = SparqlExecution.jQuery(getModel(Constant.GRAPH_TEMP), Namespace.getNsPrefixString() + "SELECT ?count WHERE {?s rdfs:comment ?count ; rdfs:label '" + search.getAudience() + "' .}", "count");
                    } else if (StringUtils.isNotBlank(search.getGenre())) {
                        results = SparqlExecution.jQuery(getModel(Constant.GRAPH_TEMP), Namespace.getNsPrefixString() + "SELECT ?count WHERE {?s rdfs:comment ?count ; rdfs:label '" + search.getGenre() + "' .}", "count");
                    } else if (StringUtils.isNotBlank(search.getLanguage())) {
                        results = SparqlExecution.jQuery(getModel(Constant.GRAPH_TEMP), Namespace.getNsPrefixString() + "SELECT ?count WHERE {?s rdfs:comment ?count ; rdfs:label '" + search.getLanguage() + "' .}", "count");
                    } else {
                        results = SparqlExecution.jQuery(getModel(Constant.GRAPH_TEMP), Namespace.getNsPrefixString() + "SELECT ?count WHERE {<http://data.library.sh.cn/work/count> rdfs:comment ?count .}", "count");
                    }

                    count = Long.parseLong(((Map) results.get(0)).get("count").toString());
                } else {
                    count = pager.getRowCount();
                }
            } else {
                if (pager.getRowCount() == 0) {
                    results = SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_COUNT_WORK_Q.toString(clause), "count");
                    count = Long.parseLong(RDFUtils.getValue(((Map) results.get(0)).get("count").toString()));
                } else {
                    count = pager.getRowCount();
                }
            }

            result.setTotalrecord(count);
            if(count > 0) {
                results = SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_QUERY_WORK_Q.toString(clause, sort, pager.getStartIndex(), pager.getPageSize()), "uri");

                for (int i=0; i<results.size(); i++) {
                    String uri = ((Map) results.get(i)).get("uri").toString();
                    Map info = (Map) SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_QUERY_WORK_INFO.toString(uri), "creator", "note", "label").get(0);
                    ((Map) results.get(i)).put("creator", info.get("creator") != null ? info.get("creator").toString() : "");
                    ((Map) results.get(i)).put("note", info.get("note") != null ? info.get("note").toString() : "");
                    ((Map) results.get(i)).put("label", info.get("label") != null ? RDFUtils.getValue(info.get("label").toString()) : "");
                    ((Map) results.get(i)).put("hor", this.getCoverHor(uri));
                }
                result.setResultList(RDFUtils.transformListMap(results));
            }
//        }

        return result;
    }

    @Override
    public List<Map<String, String>> countFacetWorks(WorkSearchBean search) {
        String clause = MergeParts.workSearch(search);

        return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_FACET_WORK_Q.toString(clause), "cnt", "facet_text", "value", "context"));
    }

    @Override
    public List<Map<String, String>> countWorkFacet(WorkSearchBean search, String facet) {
        if (isBlank(search)) {
            //Get statistics from temp graph
            if ("bf:intendedAudience/bf:identifiedBy".equals(facet)) {
                return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_TEMP), RdfQuery.RDF_QUERY_WORK_FACET.toString("bf:IntendedAudience"), "cnt", "facet_text"));
            }

            if ("bf:genreForm/bf:identifiedBy".equals(facet)) {
                return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_TEMP), RdfQuery.RDF_QUERY_WORK_FACET.toString("bf:GenreForm"), "cnt", "facet_text"));
            }

            if ("bf:language/bf:identifiedBy".equals(facet)) {
                return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_TEMP), RdfQuery.RDF_QUERY_WORK_FACET.toString("bf:Language"), "cnt", "facet_text"));
            }

            return null;
        } else {
            String clause = MergeParts.workSearch(search);

            if ("bf:language/bf:identifiedBy".equals(facet)) {
                return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_FACET_WORK_LANGUAGE.toString(clause), "cnt", "facet_text"));
            }

            return RDFUtils.transformListMap(SparqlExecution.vQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_FACET_WORK_CS.toString(clause, facet), "cnt", "facet_text"));
        }
    }

    @Override
    public void updateFacetWork(String facet, String type) {
        //Remove
        SparqlExecution.update(graph, Namespace.getNsPrefixString() + " WITH <" + Constant.GRAPH_TEMP + "> DELETE {?s ?p ?o} WHERE {?s a " + type + " ; ?p ?o .}");

        //Statistics
        ArrayList results = null;
        if (facet.equals("bf:language/bf:identifiedBy")) {
            results = SparqlExecution.vQuery(graph, RdfQuery.RDF_COUNT_WORK_FACET_LANGUAGE.toString(), "uri", "count", "facet");
        } else {
            results = SparqlExecution.vQuery(graph, RdfQuery.RDF_COUNT_WORK_FACET.toString(facet), "uri", "count", "facet");
        }

//        com.hp.hpl.jena.rdf.model.Model model = ModelFactory.createDefaultModel();

        for (int i=0; i<results.size(); i++) {
            String uri = ((Map) results.get(i)).get("uri").toString();
            String count = RDFUtils.getValue(((Map) results.get(i)).get("count").toString());
            String facet_text = ((Map)results.get(i)).get("facet").toString();
//            String utype = Namespace.getURIByName(type.split(":")[0]) + type.split(":")[1];

//            com.hp.hpl.jena.rdf.model.Resource res = model.createResource(uri);
//            res.addProperty(RDFS.comment, RDFUtils.getValue(count))
//                    .addProperty(RDFS.label, facet_text)
//                    .addProperty(RDF.type, model.createResource(utype));
            String str = Namespace.getNsPrefixString() + "WITH <" + Constant.GRAPH_TEMP + "> " +
                    "INSERT DATA {" +
                    "   <" + uri + "> rdfs:label '" + facet_text + "' ; " +
                    "       rdfs:comment '" + count + "' ; " +
                    "       rdf:type " + type + " . }";
            SparqlExecution.update(graph, str);
            System.out.println("Finished [" + type + " - " + (i+1) + "/" + results.size() + "]");
        }

//        try {
//            getModel(Constant.GRAPH_TEMP).add(model);
//        } finally {
//            model.close();
//        }
    }

    @Override
    public void countWork() {
        ArrayList results = SparqlExecution.jQuery(getModel(Constant.GRAPH_UNIFY), RdfQuery.RDF_COUNT_WORK_Q.toString(""), "count");

        String count = RDFUtils.getValue(((Map) results.get(0)).get("count").toString());

        com.hp.hpl.jena.rdf.model.Model model = getModel(Constant.GRAPH_TEMP);
        com.hp.hpl.jena.rdf.model.Resource res = model.createResource("http://data.library.sh.cn/work/count");

        res.addProperty(RDFS.comment, RDFUtils.getValue(count));
    }

    private boolean isBlank(WorkSearchBean search) {
        if (StringUtils.isNotBlank(search.getFreetext()) || StringUtils.isNotBlank(search.getTitle()) || StringUtils.isNotBlank(search.getPerson())
                || StringUtils.isNotBlank(search.getStartYear()) || StringUtils.isNotBlank(search.getEndYear()) || StringUtils.isNotBlank(search.getPublisher())
                || StringUtils.isNotBlank(search.getAudience()) || StringUtils.isNotBlank(search.getGenre()) || StringUtils.isNotBlank(search.getLanguage())
                || StringUtils.isNotBlank(search.getYear()) || StringUtils.isNotBlank(search.getClassification()) || StringUtils.isNotBlank(search.getSubject())) {
            return false;
        }

        return true;
    }

    private boolean isSearchBlank(WorkSearchBean search) {
        if (StringUtils.isNotBlank(search.getFreetext()) || StringUtils.isNotBlank(search.getTitle()) || StringUtils.isNotBlank(search.getPerson())
                || StringUtils.isNotBlank(search.getStartYear()) || StringUtils.isNotBlank(search.getEndYear()) || StringUtils.isNotBlank(search.getPublisher())
                || StringUtils.isNotBlank(search.getAudience()) || StringUtils.isNotBlank(search.getGenre()) || StringUtils.isNotBlank(search.getLanguage())
                || StringUtils.isNotBlank(search.getYear()) || StringUtils.isNotBlank(search.getClassification()) || StringUtils.isNotBlank(search.getSubject())) {
            return false;
        }

        return true;
    }

    @Override
    public Map<String, String> getWorkInfos(String work_uri) {
        Model model_op = ModelManager.get(getModel(Constant.GRAPH_UNIFY));

        return RDFUtils.transformQueryResultTable(model_op.sparqlSelect(RdfQuery.RDF_QUERY_WORK_DETAIL.toString(work_uri))).get(0);
    }

    @Override
    public String getCoverHor(String work_uri) {
        ArrayList results = SparqlExecution.vQuery(getModel(Constant.GRAPH_INSTANCE), RdfQuery.RDF_QUERY_WORK_COVER_HOR.toString(work_uri), "hor");

        if (results.size() > 0) {
            return ((Map) results.get(0)).get("hor").toString();
        }

        return "";
    }

    @Override
    public QueryResult<Map<String, String>> getRemotePersons(String person, String order, int start, int size) {
        QueryResult<Map<String, String>> result = new QueryResult<>();

        ArrayList rst = SparqlExecution.rQuery(appConfig.getLocal(), RdfQuery.RDF_COUNT_WORK_REMOTE_PERSONS.toString(appConfig.getRemote(), person), "count");

        Long count = Long.parseLong(RDFUtils.getValue(((Map) rst.get(0)).get("count").toString()));

        result.setTotalrecord(count);
        if(count > 0) {
            rst = SparqlExecution.rQuery(appConfig.getLocal(), RdfQuery.RDF_QUERY_WORK_REMOTE_PERSONS.toString(appConfig.getRemote(), person, order, start, size), "uri", "name", "birthday", "deathday", "brief");
            result.setResultList(RDFUtils.transformListMap(rst));
        }

        return result;
    }

    @Override
    public List<Map<String, String>> getRemotePersons(String person) {
//        com.hp.hpl.jena.rdf.model.Model temp = ModelFactory.createDefaultModel();

//        temp.add(SparqlExecution.rConstruct(appConfig.getLocal(), RdfQuery.RDF_CONSTRUCT_WORK_REMOTE_PERSONS.toString(appConfig.getRemote(), person)));
//        com.hp.hpl.jena.rdf.model.Model model = getModel(Constant.GRAPH_WORK);
//        model.add(temp);

//        return RDFUtils.transformListMap(SparqlExecution.jQuery(model, RdfQuery.RDF_QUERY_WORK_REMOTE_PERSONS_1.toString(), "uri", "name", "birthday", "deathday", "brief"));
        ArrayList results = SparqlExecution.rQuery(appConfig.getLocal(), RdfQuery.RDF_QUERY_WORK_REMOTE_PERSONS.toString(appConfig.getRemote(), person), "uri", "name", "birthday", "deathday");

        for (int i=0; i<results.size(); i++) {
            String uri = ((Map) results.get(i)).get("uri").toString();
            ArrayList briefs = SparqlExecution.rQuery(appConfig.getLocal(), RdfQuery.RDF_QUERY_WORK_REMOTE_PERSON_BRIEF.toString(appConfig.getRemote(), uri), "brief");

            if (briefs.size() > 0) {
                ((Map) results.get(i)).put("brief", ((Map) briefs.get(0)).get("brief").toString());
            }
        }

        return RDFUtils.transformListMap(results);
    }
}
